// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/compiler/backend/instruction-scheduler.h"
#include "src/macro-assembler.h"

namespace v8 {
namespace internal {
    namespace compiler {

        bool InstructionScheduler::SchedulerSupported() { return true; }

        int InstructionScheduler::GetTargetInstructionFlags(
            const Instruction* instr) const
        {
            switch (instr->arch_opcode()) {
            case kMips64AbsD:
            case kMips64AbsS:
            case kMips64Add:
            case kMips64AddD:
            case kMips64AddS:
            case kMips64And:
            case kMips64And32:
            case kMips64AssertEqual:
            case kMips64BitcastDL:
            case kMips64BitcastLD:
            case kMips64ByteSwap32:
            case kMips64ByteSwap64:
            case kMips64CeilWD:
            case kMips64CeilWS:
            case kMips64Clz:
            case kMips64Cmp:
            case kMips64CmpD:
            case kMips64CmpS:
            case kMips64Ctz:
            case kMips64CvtDL:
            case kMips64CvtDS:
            case kMips64CvtDUl:
            case kMips64CvtDUw:
            case kMips64CvtDW:
            case kMips64CvtSD:
            case kMips64CvtSL:
            case kMips64CvtSUl:
            case kMips64CvtSUw:
            case kMips64CvtSW:
            case kMips64DMulHigh:
            case kMips64MulHighU:
            case kMips64Dadd:
            case kMips64DaddOvf:
            case kMips64Dclz:
            case kMips64Dctz:
            case kMips64Ddiv:
            case kMips64DdivU:
            case kMips64Dext:
            case kMips64Dins:
            case kMips64Div:
            case kMips64DivD:
            case kMips64DivS:
            case kMips64DivU:
            case kMips64Dlsa:
            case kMips64Dmod:
            case kMips64DmodU:
            case kMips64Dmul:
            case kMips64Dpopcnt:
            case kMips64Dror:
            case kMips64Dsar:
            case kMips64Dshl:
            case kMips64Dshr:
            case kMips64Dsub:
            case kMips64DsubOvf:
            case kMips64Ext:
            case kMips64F32x4Abs:
            case kMips64F32x4Add:
            case kMips64F32x4AddHoriz:
            case kMips64F32x4Eq:
            case kMips64F32x4ExtractLane:
            case kMips64F32x4Lt:
            case kMips64F32x4Le:
            case kMips64F32x4Max:
            case kMips64F32x4Min:
            case kMips64F32x4Mul:
            case kMips64F32x4Ne:
            case kMips64F32x4Neg:
            case kMips64F32x4RecipApprox:
            case kMips64F32x4RecipSqrtApprox:
            case kMips64F32x4ReplaceLane:
            case kMips64F32x4SConvertI32x4:
            case kMips64F32x4Splat:
            case kMips64F32x4Sub:
            case kMips64F32x4UConvertI32x4:
            case kMips64Float32Max:
            case kMips64Float32Min:
            case kMips64Float32RoundDown:
            case kMips64Float32RoundTiesEven:
            case kMips64Float32RoundTruncate:
            case kMips64Float32RoundUp:
            case kMips64Float64ExtractLowWord32:
            case kMips64Float64ExtractHighWord32:
            case kMips64Float64InsertLowWord32:
            case kMips64Float64InsertHighWord32:
            case kMips64Float64Max:
            case kMips64Float64Min:
            case kMips64Float64RoundDown:
            case kMips64Float64RoundTiesEven:
            case kMips64Float64RoundTruncate:
            case kMips64Float64RoundUp:
            case kMips64Float64SilenceNaN:
            case kMips64FloorWD:
            case kMips64FloorWS:
            case kMips64I16x8Add:
            case kMips64I16x8AddHoriz:
            case kMips64I16x8AddSaturateS:
            case kMips64I16x8AddSaturateU:
            case kMips64I16x8Eq:
            case kMips64I16x8ExtractLane:
            case kMips64I16x8GeS:
            case kMips64I16x8GeU:
            case kMips64I16x8GtS:
            case kMips64I16x8GtU:
            case kMips64I16x8MaxS:
            case kMips64I16x8MaxU:
            case kMips64I16x8MinS:
            case kMips64I16x8MinU:
            case kMips64I16x8Mul:
            case kMips64I16x8Ne:
            case kMips64I16x8Neg:
            case kMips64I16x8ReplaceLane:
            case kMips64I8x16SConvertI16x8:
            case kMips64I16x8SConvertI32x4:
            case kMips64I16x8SConvertI8x16High:
            case kMips64I16x8SConvertI8x16Low:
            case kMips64I16x8Shl:
            case kMips64I16x8ShrS:
            case kMips64I16x8ShrU:
            case kMips64I16x8Splat:
            case kMips64I16x8Sub:
            case kMips64I16x8SubSaturateS:
            case kMips64I16x8SubSaturateU:
            case kMips64I8x16UConvertI16x8:
            case kMips64I16x8UConvertI32x4:
            case kMips64I16x8UConvertI8x16High:
            case kMips64I16x8UConvertI8x16Low:
            case kMips64I32x4Add:
            case kMips64I32x4AddHoriz:
            case kMips64I32x4Eq:
            case kMips64I32x4ExtractLane:
            case kMips64I32x4GeS:
            case kMips64I32x4GeU:
            case kMips64I32x4GtS:
            case kMips64I32x4GtU:
            case kMips64I32x4MaxS:
            case kMips64I32x4MaxU:
            case kMips64I32x4MinS:
            case kMips64I32x4MinU:
            case kMips64I32x4Mul:
            case kMips64I32x4Ne:
            case kMips64I32x4Neg:
            case kMips64I32x4ReplaceLane:
            case kMips64I32x4SConvertF32x4:
            case kMips64I32x4SConvertI16x8High:
            case kMips64I32x4SConvertI16x8Low:
            case kMips64I32x4Shl:
            case kMips64I32x4ShrS:
            case kMips64I32x4ShrU:
            case kMips64I32x4Splat:
            case kMips64I32x4Sub:
            case kMips64I32x4UConvertF32x4:
            case kMips64I32x4UConvertI16x8High:
            case kMips64I32x4UConvertI16x8Low:
            case kMips64I8x16Add:
            case kMips64I8x16AddSaturateS:
            case kMips64I8x16AddSaturateU:
            case kMips64I8x16Eq:
            case kMips64I8x16ExtractLane:
            case kMips64I8x16GeS:
            case kMips64I8x16GeU:
            case kMips64I8x16GtS:
            case kMips64I8x16GtU:
            case kMips64I8x16MaxS:
            case kMips64I8x16MaxU:
            case kMips64I8x16MinS:
            case kMips64I8x16MinU:
            case kMips64I8x16Mul:
            case kMips64I8x16Ne:
            case kMips64I8x16Neg:
            case kMips64I8x16ReplaceLane:
            case kMips64I8x16Shl:
            case kMips64I8x16ShrS:
            case kMips64I8x16ShrU:
            case kMips64I8x16Splat:
            case kMips64I8x16Sub:
            case kMips64I8x16SubSaturateS:
            case kMips64I8x16SubSaturateU:
            case kMips64Ins:
            case kMips64Lsa:
            case kMips64MaxD:
            case kMips64MaxS:
            case kMips64MinD:
            case kMips64MinS:
            case kMips64Mod:
            case kMips64ModU:
            case kMips64Mov:
            case kMips64Mul:
            case kMips64MulD:
            case kMips64MulHigh:
            case kMips64MulOvf:
            case kMips64MulS:
            case kMips64NegD:
            case kMips64NegS:
            case kMips64Nor:
            case kMips64Nor32:
            case kMips64Or:
            case kMips64Or32:
            case kMips64Popcnt:
            case kMips64Ror:
            case kMips64RoundWD:
            case kMips64RoundWS:
            case kMips64S128And:
            case kMips64S128Or:
            case kMips64S128Not:
            case kMips64S128Select:
            case kMips64S128Xor:
            case kMips64S128Zero:
            case kMips64S16x8InterleaveEven:
            case kMips64S16x8InterleaveOdd:
            case kMips64S16x8InterleaveLeft:
            case kMips64S16x8InterleaveRight:
            case kMips64S16x8PackEven:
            case kMips64S16x8PackOdd:
            case kMips64S16x2Reverse:
            case kMips64S16x4Reverse:
            case kMips64S1x16AllTrue:
            case kMips64S1x16AnyTrue:
            case kMips64S1x4AllTrue:
            case kMips64S1x4AnyTrue:
            case kMips64S1x8AllTrue:
            case kMips64S1x8AnyTrue:
            case kMips64S32x4InterleaveEven:
            case kMips64S32x4InterleaveOdd:
            case kMips64S32x4InterleaveLeft:
            case kMips64S32x4InterleaveRight:
            case kMips64S32x4PackEven:
            case kMips64S32x4PackOdd:
            case kMips64S32x4Shuffle:
            case kMips64S8x16Concat:
            case kMips64S8x16InterleaveEven:
            case kMips64S8x16InterleaveOdd:
            case kMips64S8x16InterleaveLeft:
            case kMips64S8x16InterleaveRight:
            case kMips64S8x16PackEven:
            case kMips64S8x16PackOdd:
            case kMips64S8x2Reverse:
            case kMips64S8x4Reverse:
            case kMips64S8x8Reverse:
            case kMips64S8x16Shuffle:
            case kMips64Sar:
            case kMips64Seb:
            case kMips64Seh:
            case kMips64Shl:
            case kMips64Shr:
            case kMips64SqrtD:
            case kMips64SqrtS:
            case kMips64Sub:
            case kMips64SubD:
            case kMips64SubS:
            case kMips64TruncLD:
            case kMips64TruncLS:
            case kMips64TruncUlD:
            case kMips64TruncUlS:
            case kMips64TruncUwD:
            case kMips64TruncUwS:
            case kMips64TruncWD:
            case kMips64TruncWS:
            case kMips64Tst:
            case kMips64Xor:
            case kMips64Xor32:
                return kNoOpcodeFlags;

            case kMips64Lb:
            case kMips64Lbu:
            case kMips64Ld:
            case kMips64Ldc1:
            case kMips64Lh:
            case kMips64Lhu:
            case kMips64Lw:
            case kMips64Lwc1:
            case kMips64Lwu:
            case kMips64MsaLd:
            case kMips64Peek:
            case kMips64Uld:
            case kMips64Uldc1:
            case kMips64Ulh:
            case kMips64Ulhu:
            case kMips64Ulw:
            case kMips64Ulwu:
            case kMips64Ulwc1:
            case kMips64Word64AtomicLoadUint8:
            case kMips64Word64AtomicLoadUint16:
            case kMips64Word64AtomicLoadUint32:
            case kMips64Word64AtomicLoadUint64:

                return kIsLoadOperation;

            case kMips64ModD:
            case kMips64ModS:
            case kMips64MsaSt:
            case kMips64Push:
            case kMips64Sb:
            case kMips64Sd:
            case kMips64Sdc1:
            case kMips64Sh:
            case kMips64StackClaim:
            case kMips64StoreToStackSlot:
            case kMips64Sw:
            case kMips64Swc1:
            case kMips64Usd:
            case kMips64Usdc1:
            case kMips64Ush:
            case kMips64Usw:
            case kMips64Uswc1:
            case kMips64Word64AtomicStoreWord8:
            case kMips64Word64AtomicStoreWord16:
            case kMips64Word64AtomicStoreWord32:
            case kMips64Word64AtomicStoreWord64:
            case kMips64Word64AtomicAddUint8:
            case kMips64Word64AtomicAddUint16:
            case kMips64Word64AtomicAddUint32:
            case kMips64Word64AtomicAddUint64:
            case kMips64Word64AtomicSubUint8:
            case kMips64Word64AtomicSubUint16:
            case kMips64Word64AtomicSubUint32:
            case kMips64Word64AtomicSubUint64:
            case kMips64Word64AtomicAndUint8:
            case kMips64Word64AtomicAndUint16:
            case kMips64Word64AtomicAndUint32:
            case kMips64Word64AtomicAndUint64:
            case kMips64Word64AtomicOrUint8:
            case kMips64Word64AtomicOrUint16:
            case kMips64Word64AtomicOrUint32:
            case kMips64Word64AtomicOrUint64:
            case kMips64Word64AtomicXorUint8:
            case kMips64Word64AtomicXorUint16:
            case kMips64Word64AtomicXorUint32:
            case kMips64Word64AtomicXorUint64:
            case kMips64Word64AtomicExchangeUint8:
            case kMips64Word64AtomicExchangeUint16:
            case kMips64Word64AtomicExchangeUint32:
            case kMips64Word64AtomicExchangeUint64:
            case kMips64Word64AtomicCompareExchangeUint8:
            case kMips64Word64AtomicCompareExchangeUint16:
            case kMips64Word64AtomicCompareExchangeUint32:
            case kMips64Word64AtomicCompareExchangeUint64:
                return kHasSideEffect;

#define CASE(Name) case k##Name:
                COMMON_ARCH_OPCODE_LIST(CASE)
#undef CASE
                // Already covered in architecture independent code.
                UNREACHABLE();
            }

            UNREACHABLE();
        }

        enum Latency {
            BRANCH = 4, // Estimated max.
            RINT_S = 4, // Estimated.
            RINT_D = 4, // Estimated.

            MULT = 4,
            MULTU = 4,
            DMULT = 4,
            DMULTU = 4,

            MUL = 7,
            DMUL = 7,
            MUH = 7,
            MUHU = 7,
            DMUH = 7,
            DMUHU = 7,

            DIV = 50, // Min:11 Max:50
            DDIV = 50,
            DIVU = 50,
            DDIVU = 50,

            ABS_S = 4,
            ABS_D = 4,
            NEG_S = 4,
            NEG_D = 4,
            ADD_S = 4,
            ADD_D = 4,
            SUB_S = 4,
            SUB_D = 4,
            MAX_S = 4, // Estimated.
            MIN_S = 4,
            MAX_D = 4, // Estimated.
            MIN_D = 4,
            C_cond_S = 4,
            C_cond_D = 4,
            MUL_S = 4,

            MADD_S = 4,
            MSUB_S = 4,
            NMADD_S = 4,
            NMSUB_S = 4,

            CABS_cond_S = 4,
            CABS_cond_D = 4,

            CVT_D_S = 4,
            CVT_PS_PW = 4,

            CVT_S_W = 4,
            CVT_S_L = 4,
            CVT_D_W = 4,
            CVT_D_L = 4,

            CVT_S_D = 4,

            CVT_W_S = 4,
            CVT_W_D = 4,
            CVT_L_S = 4,
            CVT_L_D = 4,

            CEIL_W_S = 4,
            CEIL_W_D = 4,
            CEIL_L_S = 4,
            CEIL_L_D = 4,

            FLOOR_W_S = 4,
            FLOOR_W_D = 4,
            FLOOR_L_S = 4,
            FLOOR_L_D = 4,

            ROUND_W_S = 4,
            ROUND_W_D = 4,
            ROUND_L_S = 4,
            ROUND_L_D = 4,

            TRUNC_W_S = 4,
            TRUNC_W_D = 4,
            TRUNC_L_S = 4,
            TRUNC_L_D = 4,

            MOV_S = 4,
            MOV_D = 4,

            MOVF_S = 4,
            MOVF_D = 4,

            MOVN_S = 4,
            MOVN_D = 4,

            MOVT_S = 4,
            MOVT_D = 4,

            MOVZ_S = 4,
            MOVZ_D = 4,

            MUL_D = 5,
            MADD_D = 5,
            MSUB_D = 5,
            NMADD_D = 5,
            NMSUB_D = 5,

            RECIP_S = 13,
            RECIP_D = 26,

            RSQRT_S = 17,
            RSQRT_D = 36,

            DIV_S = 17,
            SQRT_S = 17,

            DIV_D = 32,
            SQRT_D = 32,

            MTC1 = 4,
            MTHC1 = 4,
            DMTC1 = 4,
            LWC1 = 4,
            LDC1 = 4,

            MFC1 = 1,
            MFHC1 = 1,
            DMFC1 = 1,
            MFHI = 1,
            MFLO = 1,
            SWC1 = 1,
            SDC1 = 1,
        };

        int DadduLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                return 1;
            } else {
                return 2; // Estimated max.
            }
        }

        int DsubuLatency(bool is_operand_register = true)
        {
            return DadduLatency(is_operand_register);
        }

        int AndLatency(bool is_operand_register = true)
        {
            return DadduLatency(is_operand_register);
        }

        int OrLatency(bool is_operand_register = true)
        {
            return DadduLatency(is_operand_register);
        }

        int NorLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                return 1;
            } else {
                return 2; // Estimated max.
            }
        }

        int XorLatency(bool is_operand_register = true)
        {
            return DadduLatency(is_operand_register);
        }

        int MulLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                return Latency::MUL;
            } else {
                return Latency::MUL + 1;
            }
        }

        int DmulLatency(bool is_operand_register = true)
        {
            int latency = 0;
            if (kArchVariant >= kMips64r6) {
                latency = Latency::DMUL;
            } else {
                latency = Latency::DMULT + Latency::MFLO;
            }
            if (!is_operand_register) {
                latency += 1;
            }
            return latency;
        }

        int MulhLatency(bool is_operand_register = true)
        {
            int latency = 0;
            if (kArchVariant >= kMips64r6) {
                latency = Latency::MUH;
            } else {
                latency = Latency::MULT + Latency::MFHI;
            }
            if (!is_operand_register) {
                latency += 1;
            }
            return latency;
        }

        int MulhuLatency(bool is_operand_register = true)
        {
            int latency = 0;
            if (kArchVariant >= kMips64r6) {
                latency = Latency::MUH;
            } else {
                latency = Latency::MULTU + Latency::MFHI;
            }
            if (!is_operand_register) {
                latency += 1;
            }
            return latency;
        }

        int DMulhLatency(bool is_operand_register = true)
        {
            int latency = 0;
            if (kArchVariant >= kMips64r6) {
                latency = Latency::DMUH;
            } else {
                latency = Latency::DMULT + Latency::MFHI;
            }
            if (!is_operand_register) {
                latency += 1;
            }
            return latency;
        }

        int DivLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                return Latency::DIV;
            } else {
                return Latency::DIV + 1;
            }
        }

        int DivuLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                return Latency::DIVU;
            } else {
                return Latency::DIVU + 1;
            }
        }

        int DdivLatency(bool is_operand_register = true)
        {
            int latency = 0;
            if (kArchVariant >= kMips64r6) {
                latency = Latency::DDIV;
            } else {
                latency = Latency::DDIV + Latency::MFLO;
            }
            if (!is_operand_register) {
                latency += 1;
            }
            return latency;
        }

        int DdivuLatency(bool is_operand_register = true)
        {
            int latency = 0;
            if (kArchVariant >= kMips64r6) {
                latency = Latency::DDIVU;
            } else {
                latency = Latency::DDIVU + Latency::MFLO;
            }
            if (!is_operand_register) {
                latency += 1;
            }
            return latency;
        }

        int ModLatency(bool is_operand_register = true)
        {
            int latency = 0;
            if (kArchVariant >= kMips64r6) {
                latency = 1;
            } else {
                latency = Latency::DIV + Latency::MFHI;
            }
            if (!is_operand_register) {
                latency += 1;
            }
            return latency;
        }

        int ModuLatency(bool is_operand_register = true)
        {
            int latency = 0;
            if (kArchVariant >= kMips64r6) {
                latency = 1;
            } else {
                latency = Latency::DIVU + Latency::MFHI;
            }
            if (!is_operand_register) {
                latency += 1;
            }
            return latency;
        }

        int DmodLatency(bool is_operand_register = true)
        {
            int latency = 0;
            if (kArchVariant >= kMips64r6) {
                latency = 1;
            } else {
                latency = Latency::DDIV + Latency::MFHI;
            }
            if (!is_operand_register) {
                latency += 1;
            }
            return latency;
        }

        int DmoduLatency(bool is_operand_register = true)
        {
            int latency = 0;
            if (kArchVariant >= kMips64r6) {
                latency = 1;
            } else {
                latency = Latency::DDIV + Latency::MFHI;
            }
            if (!is_operand_register) {
                latency += 1;
            }
            return latency;
        }

        int MovzLatency()
        {
            if (kArchVariant >= kMips64r6) {
                return Latency::BRANCH + 1;
            } else {
                return 1;
            }
        }

        int MovnLatency()
        {
            if (kArchVariant >= kMips64r6) {
                return Latency::BRANCH + 1;
            } else {
                return 1;
            }
        }

        int DlsaLatency()
        {
            // Estimated max.
            return DadduLatency() + 1;
        }

        int CallLatency()
        {
            // Estimated.
            return DadduLatency(false) + Latency::BRANCH + 5;
        }

        int JumpLatency()
        {
            // Estimated max.
            return 1 + DadduLatency() + Latency::BRANCH + 2;
        }

        int SmiUntagLatency() { return 1; }

        int PrepareForTailCallLatency()
        {
            // Estimated max.
            return 2 * (DlsaLatency() + DadduLatency(false)) + 2 + Latency::BRANCH + Latency::BRANCH + 2 * DsubuLatency(false) + 2 + Latency::BRANCH + 1;
        }

        int AssemblePopArgumentsAdoptFrameLatency()
        {
            return 1 + Latency::BRANCH + 1 + SmiUntagLatency() + PrepareForTailCallLatency();
        }

        int AssertLatency() { return 1; }

        int PrepareCallCFunctionLatency()
        {
            int frame_alignment = TurboAssembler::ActivationFrameAlignment();
            if (frame_alignment > kSystemPointerSize) {
                return 1 + DsubuLatency(false) + AndLatency(false) + 1;
            } else {
                return DsubuLatency(false);
            }
        }

        int AdjustBaseAndOffsetLatency()
        {
            return 3; // Estimated max.
        }

        int AlignedMemoryLatency() { return AdjustBaseAndOffsetLatency() + 1; }

        int UlhuLatency()
        {
            if (kArchVariant >= kMips64r6) {
                return AlignedMemoryLatency();
            } else {
                return AdjustBaseAndOffsetLatency() + 2 * AlignedMemoryLatency() + 2;
            }
        }

        int UlwLatency()
        {
            if (kArchVariant >= kMips64r6) {
                return AlignedMemoryLatency();
            } else {
                // Estimated max.
                return AdjustBaseAndOffsetLatency() + 3;
            }
        }

        int UlwuLatency()
        {
            if (kArchVariant >= kMips64r6) {
                return AlignedMemoryLatency();
            } else {
                return UlwLatency() + 1;
            }
        }

        int UldLatency()
        {
            if (kArchVariant >= kMips64r6) {
                return AlignedMemoryLatency();
            } else {
                // Estimated max.
                return AdjustBaseAndOffsetLatency() + 3;
            }
        }

        int Ulwc1Latency()
        {
            if (kArchVariant >= kMips64r6) {
                return AlignedMemoryLatency();
            } else {
                return UlwLatency() + Latency::MTC1;
            }
        }

        int Uldc1Latency()
        {
            if (kArchVariant >= kMips64r6) {
                return AlignedMemoryLatency();
            } else {
                return UldLatency() + Latency::DMTC1;
            }
        }

        int UshLatency()
        {
            if (kArchVariant >= kMips64r6) {
                return AlignedMemoryLatency();
            } else {
                // Estimated max.
                return AdjustBaseAndOffsetLatency() + 2 + 2 * AlignedMemoryLatency();
            }
        }

        int UswLatency()
        {
            if (kArchVariant >= kMips64r6) {
                return AlignedMemoryLatency();
            } else {
                return AdjustBaseAndOffsetLatency() + 2;
            }
        }

        int UsdLatency()
        {
            if (kArchVariant >= kMips64r6) {
                return AlignedMemoryLatency();
            } else {
                return AdjustBaseAndOffsetLatency() + 2;
            }
        }

        int Uswc1Latency()
        {
            if (kArchVariant >= kMips64r6) {
                return AlignedMemoryLatency();
            } else {
                return Latency::MFC1 + UswLatency();
            }
        }

        int Usdc1Latency()
        {
            if (kArchVariant >= kMips64r6) {
                return AlignedMemoryLatency();
            } else {
                return Latency::DMFC1 + UsdLatency();
            }
        }

        int Lwc1Latency() { return AdjustBaseAndOffsetLatency() + Latency::LWC1; }

        int Swc1Latency() { return AdjustBaseAndOffsetLatency() + Latency::SWC1; }

        int Sdc1Latency() { return AdjustBaseAndOffsetLatency() + Latency::SDC1; }

        int Ldc1Latency() { return AdjustBaseAndOffsetLatency() + Latency::LDC1; }

        int MultiPushLatency()
        {
            int latency = DsubuLatency(false);
            for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
                latency++;
            }
            return latency;
        }

        int MultiPushFPULatency()
        {
            int latency = DsubuLatency(false);
            for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
                latency += Sdc1Latency();
            }
            return latency;
        }

        int PushCallerSavedLatency(SaveFPRegsMode fp_mode)
        {
            int latency = MultiPushLatency();
            if (fp_mode == kSaveFPRegs) {
                latency += MultiPushFPULatency();
            }
            return latency;
        }

        int MultiPopLatency()
        {
            int latency = DadduLatency(false);
            for (int16_t i = 0; i < kNumRegisters; i++) {
                latency++;
            }
            return latency;
        }

        int MultiPopFPULatency()
        {
            int latency = DadduLatency(false);
            for (int16_t i = 0; i < kNumRegisters; i++) {
                latency += Ldc1Latency();
            }
            return latency;
        }

        int PopCallerSavedLatency(SaveFPRegsMode fp_mode)
        {
            int latency = MultiPopLatency();
            if (fp_mode == kSaveFPRegs) {
                latency += MultiPopFPULatency();
            }
            return latency;
        }

        int CallCFunctionHelperLatency()
        {
            // Estimated.
            int latency = AndLatency(false) + Latency::BRANCH + 2 + CallLatency();
            if (base::OS::ActivationFrameAlignment() > kSystemPointerSize) {
                latency++;
            } else {
                latency += DadduLatency(false);
            }
            return latency;
        }

        int CallCFunctionLatency() { return 1 + CallCFunctionHelperLatency(); }

        int AssembleArchJumpLatency()
        {
            // Estimated max.
            return Latency::BRANCH;
        }

        int AssembleArchLookupSwitchLatency(const Instruction* instr)
        {
            int latency = 0;
            for (size_t index = 2; index < instr->InputCount(); index += 2) {
                latency += 1 + Latency::BRANCH;
            }
            return latency + AssembleArchJumpLatency();
        }

        int GenerateSwitchTableLatency()
        {
            int latency = 0;
            if (kArchVariant >= kMips64r6) {
                latency = DlsaLatency() + 2;
            } else {
                latency = 6;
            }
            latency += 2;
            return latency;
        }

        int AssembleArchTableSwitchLatency()
        {
            return Latency::BRANCH + GenerateSwitchTableLatency();
        }

        int DropAndRetLatency()
        {
            // Estimated max.
            return DadduLatency(false) + JumpLatency();
        }

        int AssemblerReturnLatency()
        {
            // Estimated max.
            return DadduLatency(false) + MultiPopLatency() + MultiPopFPULatency() + Latency::BRANCH + DadduLatency() + 1 + DropAndRetLatency();
        }

        int TryInlineTruncateDoubleToILatency()
        {
            return 2 + Latency::TRUNC_W_D + Latency::MFC1 + 2 + AndLatency(false) + Latency::BRANCH;
        }

        int CallStubDelayedLatency() { return 1 + CallLatency(); }

        int TruncateDoubleToIDelayedLatency()
        {
            // TODO(mips): This no longer reflects how TruncateDoubleToI is called.
            return TryInlineTruncateDoubleToILatency() + 1 + DsubuLatency(false) + Sdc1Latency() + CallStubDelayedLatency() + DadduLatency(false) + 1;
        }

        int CheckPageFlagLatency()
        {
            return AndLatency(false) + AlignedMemoryLatency() + AndLatency(false) + Latency::BRANCH;
        }

        int SltuLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                return 1;
            } else {
                return 2; // Estimated max.
            }
        }

        int BranchShortHelperR6Latency()
        {
            return 2; // Estimated max.
        }

        int BranchShortHelperLatency()
        {
            return SltuLatency() + 2; // Estimated max.
        }

        int BranchShortLatency(BranchDelaySlot bdslot = PROTECT)
        {
            if (kArchVariant >= kMips64r6 && bdslot == PROTECT) {
                return BranchShortHelperR6Latency();
            } else {
                return BranchShortHelperLatency();
            }
        }

        int MoveLatency() { return 1; }

        int MovToFloatParametersLatency() { return 2 * MoveLatency(); }

        int MovFromFloatResultLatency() { return MoveLatency(); }

        int DaddOverflowLatency()
        {
            // Estimated max.
            return 6;
        }

        int DsubOverflowLatency()
        {
            // Estimated max.
            return 6;
        }

        int MulOverflowLatency()
        {
            // Estimated max.
            return MulLatency() + MulhLatency() + 2;
        }

        int DclzLatency() { return 1; }

        int CtzLatency()
        {
            if (kArchVariant >= kMips64r6) {
                return 3 + DclzLatency();
            } else {
                return DadduLatency(false) + XorLatency() + AndLatency() + DclzLatency() + 1 + DsubuLatency();
            }
        }

        int DctzLatency()
        {
            if (kArchVariant >= kMips64r6) {
                return 4;
            } else {
                return DadduLatency(false) + XorLatency() + AndLatency() + 1 + DsubuLatency();
            }
        }

        int PopcntLatency()
        {
            return 2 + AndLatency() + DsubuLatency() + 1 + AndLatency() + 1 + AndLatency() + DadduLatency() + 1 + DadduLatency() + 1 + AndLatency() + 1 + MulLatency() + 1;
        }

        int DpopcntLatency()
        {
            return 2 + AndLatency() + DsubuLatency() + 1 + AndLatency() + 1 + AndLatency() + DadduLatency() + 1 + DadduLatency() + 1 + AndLatency() + 1 + DmulLatency() + 1;
        }

        int CompareFLatency() { return Latency::C_cond_S; }

        int CompareF32Latency() { return CompareFLatency(); }

        int CompareF64Latency() { return CompareFLatency(); }

        int CompareIsNanFLatency() { return CompareFLatency(); }

        int CompareIsNanF32Latency() { return CompareIsNanFLatency(); }

        int CompareIsNanF64Latency() { return CompareIsNanFLatency(); }

        int NegsLatency()
        {
            if (kArchVariant >= kMips64r6) {
                return Latency::NEG_S;
            } else {
                // Estimated.
                return CompareIsNanF32Latency() + 2 * Latency::BRANCH + Latency::NEG_S + Latency::MFC1 + 1 + XorLatency() + Latency::MTC1;
            }
        }

        int NegdLatency()
        {
            if (kArchVariant >= kMips64r6) {
                return Latency::NEG_D;
            } else {
                // Estimated.
                return CompareIsNanF64Latency() + 2 * Latency::BRANCH + Latency::NEG_D + Latency::DMFC1 + 1 + XorLatency() + Latency::DMTC1;
            }
        }

        int Float64RoundLatency()
        {
            if (kArchVariant >= kMips64r6) {
                return Latency::RINT_D + 4;
            } else {
                // For ceil_l_d, floor_l_d, round_l_d, trunc_l_d latency is 4.
                return Latency::DMFC1 + 1 + Latency::BRANCH + Latency::MOV_D + 4 + Latency::DMFC1 + Latency::BRANCH + Latency::CVT_D_L + 2 + Latency::MTHC1;
            }
        }

        int Float32RoundLatency()
        {
            if (kArchVariant >= kMips64r6) {
                return Latency::RINT_S + 4;
            } else {
                // For ceil_w_s, floor_w_s, round_w_s, trunc_w_s latency is 4.
                return Latency::MFC1 + 1 + Latency::BRANCH + Latency::MOV_S + 4 + Latency::MFC1 + Latency::BRANCH + Latency::CVT_S_W + 2 + Latency::MTC1;
            }
        }

        int Float32MaxLatency()
        {
            // Estimated max.
            int latency = CompareIsNanF32Latency() + Latency::BRANCH;
            if (kArchVariant >= kMips64r6) {
                return latency + Latency::MAX_S;
            } else {
                return latency + 5 * Latency::BRANCH + 2 * CompareF32Latency() + Latency::MFC1 + 1 + Latency::MOV_S;
            }
        }

        int Float64MaxLatency()
        {
            // Estimated max.
            int latency = CompareIsNanF64Latency() + Latency::BRANCH;
            if (kArchVariant >= kMips64r6) {
                return latency + Latency::MAX_D;
            } else {
                return latency + 5 * Latency::BRANCH + 2 * CompareF64Latency() + Latency::DMFC1 + Latency::MOV_D;
            }
        }

        int Float32MinLatency()
        {
            // Estimated max.
            int latency = CompareIsNanF32Latency() + Latency::BRANCH;
            if (kArchVariant >= kMips64r6) {
                return latency + Latency::MIN_S;
            } else {
                return latency + 5 * Latency::BRANCH + 2 * CompareF32Latency() + Latency::MFC1 + 1 + Latency::MOV_S;
            }
        }

        int Float64MinLatency()
        {
            // Estimated max.
            int latency = CompareIsNanF64Latency() + Latency::BRANCH;
            if (kArchVariant >= kMips64r6) {
                return latency + Latency::MIN_D;
            } else {
                return latency + 5 * Latency::BRANCH + 2 * CompareF32Latency() + Latency::DMFC1 + Latency::MOV_D;
            }
        }

        int TruncLSLatency(bool load_status)
        {
            int latency = Latency::TRUNC_L_S + Latency::DMFC1;
            if (load_status) {
                latency += SltuLatency() + 7;
            }
            return latency;
        }

        int TruncLDLatency(bool load_status)
        {
            int latency = Latency::TRUNC_L_D + Latency::DMFC1;
            if (load_status) {
                latency += SltuLatency() + 7;
            }
            return latency;
        }

        int TruncUlSLatency()
        {
            // Estimated max.
            return 2 * CompareF32Latency() + CompareIsNanF32Latency() + 4 * Latency::BRANCH + Latency::SUB_S + 2 * Latency::TRUNC_L_S + 3 * Latency::DMFC1 + OrLatency() + Latency::MTC1 + Latency::MOV_S + SltuLatency() + 4;
        }

        int TruncUlDLatency()
        {
            // Estimated max.
            return 2 * CompareF64Latency() + CompareIsNanF64Latency() + 4 * Latency::BRANCH + Latency::SUB_D + 2 * Latency::TRUNC_L_D + 3 * Latency::DMFC1 + OrLatency() + Latency::DMTC1 + Latency::MOV_D + SltuLatency() + 4;
        }

        int PushLatency() { return DadduLatency() + AlignedMemoryLatency(); }

        int ByteSwapSignedLatency() { return 2; }

        int LlLatency(int offset)
        {
            bool is_one_instruction = (kArchVariant == kMips64r6) ? is_int9(offset) : is_int16(offset);
            if (is_one_instruction) {
                return 1;
            } else {
                return 3;
            }
        }

        int ExtractBitsLatency(bool sign_extend, int size)
        {
            int latency = 2;
            if (sign_extend) {
                switch (size) {
                case 8:
                case 16:
                case 32:
                    latency += 1;
                    break;
                default:
                    UNREACHABLE();
                }
            }
            return latency;
        }

        int InsertBitsLatency() { return 2 + DsubuLatency(false) + 2; }

        int ScLatency(int offset)
        {
            bool is_one_instruction = (kArchVariant == kMips64r6) ? is_int9(offset) : is_int16(offset);
            if (is_one_instruction) {
                return 1;
            } else {
                return 3;
            }
        }

        int Word32AtomicExchangeLatency(bool sign_extend, int size)
        {
            return DadduLatency(false) + 1 + DsubuLatency() + 2 + LlLatency(0) + ExtractBitsLatency(sign_extend, size) + InsertBitsLatency() + ScLatency(0) + BranchShortLatency() + 1;
        }

        int Word32AtomicCompareExchangeLatency(bool sign_extend, int size)
        {
            return 2 + DsubuLatency() + 2 + LlLatency(0) + ExtractBitsLatency(sign_extend, size) + InsertBitsLatency() + ScLatency(0) + BranchShortLatency() + 1;
        }

        int InstructionScheduler::GetInstructionLatency(const Instruction* instr)
        {
            // Basic latency modeling for MIPS64 instructions. They have been determined
            // in empirical way.
            switch (instr->arch_opcode()) {
            case kArchCallCodeObject:
            case kArchCallWasmFunction:
                return CallLatency();
            case kArchTailCallCodeObjectFromJSFunction:
            case kArchTailCallCodeObject: {
                int latency = 0;
                if (instr->arch_opcode() == kArchTailCallCodeObjectFromJSFunction) {
                    latency = AssemblePopArgumentsAdoptFrameLatency();
                }
                return latency + JumpLatency();
            }
            case kArchTailCallWasm:
            case kArchTailCallAddress:
                return JumpLatency();
            case kArchCallJSFunction: {
                int latency = 0;
                if (FLAG_debug_code) {
                    latency = 1 + AssertLatency();
                }
                return latency + 1 + DadduLatency(false) + CallLatency();
            }
            case kArchPrepareCallCFunction:
                return PrepareCallCFunctionLatency();
            case kArchSaveCallerRegisters: {
                auto fp_mode = static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode()));
                return PushCallerSavedLatency(fp_mode);
            }
            case kArchRestoreCallerRegisters: {
                auto fp_mode = static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode()));
                return PopCallerSavedLatency(fp_mode);
            }
            case kArchPrepareTailCall:
                return 2;
            case kArchCallCFunction:
                return CallCFunctionLatency();
            case kArchJmp:
                return AssembleArchJumpLatency();
            case kArchLookupSwitch:
                return AssembleArchLookupSwitchLatency(instr);
            case kArchTableSwitch:
                return AssembleArchTableSwitchLatency();
            case kArchDebugAbort:
                return CallLatency() + 1;
            case kArchDebugBreak:
                return 1;
            case kArchComment:
            case kArchNop:
            case kArchThrowTerminator:
            case kArchDeoptimize:
                return 0;
            case kArchRet:
                return AssemblerReturnLatency();
            case kArchStackPointer:
            case kArchFramePointer:
                return 1;
            case kArchParentFramePointer:
                // Estimated max.
                return AlignedMemoryLatency();
            case kArchTruncateDoubleToI:
                return TruncateDoubleToIDelayedLatency();
            case kArchStoreWithWriteBarrier:
                return DadduLatency() + 1 + CheckPageFlagLatency();
            case kArchStackSlot:
                // Estimated max.
                return DadduLatency(false) + AndLatency(false) + AssertLatency() + DadduLatency(false) + AndLatency(false) + BranchShortLatency() + 1 + DsubuLatency() + DadduLatency();
            case kArchWordPoisonOnSpeculation:
                return AndLatency();
            case kIeee754Float64Acos:
            case kIeee754Float64Acosh:
            case kIeee754Float64Asin:
            case kIeee754Float64Asinh:
            case kIeee754Float64Atan:
            case kIeee754Float64Atanh:
            case kIeee754Float64Atan2:
            case kIeee754Float64Cos:
            case kIeee754Float64Cosh:
            case kIeee754Float64Cbrt:
            case kIeee754Float64Exp:
            case kIeee754Float64Expm1:
            case kIeee754Float64Log:
            case kIeee754Float64Log1p:
            case kIeee754Float64Log10:
            case kIeee754Float64Log2:
            case kIeee754Float64Pow:
            case kIeee754Float64Sin:
            case kIeee754Float64Sinh:
            case kIeee754Float64Tan:
            case kIeee754Float64Tanh:
                return PrepareCallCFunctionLatency() + MovToFloatParametersLatency() + CallCFunctionLatency() + MovFromFloatResultLatency();
            case kMips64Add:
            case kMips64Dadd:
                return DadduLatency(instr->InputAt(1)->IsRegister());
            case kMips64DaddOvf:
                return DaddOverflowLatency();
            case kMips64Sub:
            case kMips64Dsub:
                return DsubuLatency(instr->InputAt(1)->IsRegister());
            case kMips64DsubOvf:
                return DsubOverflowLatency();
            case kMips64Mul:
                return MulLatency();
            case kMips64MulOvf:
                return MulOverflowLatency();
            case kMips64MulHigh:
                return MulhLatency();
            case kMips64MulHighU:
                return MulhuLatency();
            case kMips64DMulHigh:
                return DMulhLatency();
            case kMips64Div: {
                int latency = DivLatency(instr->InputAt(1)->IsRegister());
                if (kArchVariant >= kMips64r6) {
                    return latency++;
                } else {
                    return latency + MovzLatency();
                }
            }
            case kMips64DivU: {
                int latency = DivuLatency(instr->InputAt(1)->IsRegister());
                if (kArchVariant >= kMips64r6) {
                    return latency++;
                } else {
                    return latency + MovzLatency();
                }
            }
            case kMips64Mod:
                return ModLatency();
            case kMips64ModU:
                return ModuLatency();
            case kMips64Dmul:
                return DmulLatency();
            case kMips64Ddiv: {
                int latency = DdivLatency();
                if (kArchVariant >= kMips64r6) {
                    return latency++;
                } else {
                    return latency + MovzLatency();
                }
            }
            case kMips64DdivU: {
                int latency = DdivuLatency();
                if (kArchVariant >= kMips64r6) {
                    return latency++;
                } else {
                    return latency + MovzLatency();
                }
            }
            case kMips64Dmod:
                return DmodLatency();
            case kMips64DmodU:
                return DmoduLatency();
            case kMips64Dlsa:
            case kMips64Lsa:
                return DlsaLatency();
            case kMips64And:
                return AndLatency(instr->InputAt(1)->IsRegister());
            case kMips64And32: {
                bool is_operand_register = instr->InputAt(1)->IsRegister();
                int latency = AndLatency(is_operand_register);
                if (is_operand_register) {
                    return latency + 2;
                } else {
                    return latency + 1;
                }
            }
            case kMips64Or:
                return OrLatency(instr->InputAt(1)->IsRegister());
            case kMips64Or32: {
                bool is_operand_register = instr->InputAt(1)->IsRegister();
                int latency = OrLatency(is_operand_register);
                if (is_operand_register) {
                    return latency + 2;
                } else {
                    return latency + 1;
                }
            }
            case kMips64Nor:
                return NorLatency(instr->InputAt(1)->IsRegister());
            case kMips64Nor32: {
                bool is_operand_register = instr->InputAt(1)->IsRegister();
                int latency = NorLatency(is_operand_register);
                if (is_operand_register) {
                    return latency + 2;
                } else {
                    return latency + 1;
                }
            }
            case kMips64Xor:
                return XorLatency(instr->InputAt(1)->IsRegister());
            case kMips64Xor32: {
                bool is_operand_register = instr->InputAt(1)->IsRegister();
                int latency = XorLatency(is_operand_register);
                if (is_operand_register) {
                    return latency + 2;
                } else {
                    return latency + 1;
                }
            }
            case kMips64Clz:
            case kMips64Dclz:
                return DclzLatency();
            case kMips64Ctz:
                return CtzLatency();
            case kMips64Dctz:
                return DctzLatency();
            case kMips64Popcnt:
                return PopcntLatency();
            case kMips64Dpopcnt:
                return DpopcntLatency();
            case kMips64Shl:
                return 1;
            case kMips64Shr:
            case kMips64Sar:
                return 2;
            case kMips64Ext:
            case kMips64Ins:
            case kMips64Dext:
            case kMips64Dins:
            case kMips64Dshl:
            case kMips64Dshr:
            case kMips64Dsar:
            case kMips64Ror:
            case kMips64Dror:
                return 1;
            case kMips64Tst:
                return AndLatency(instr->InputAt(1)->IsRegister());
            case kMips64Mov:
                return 1;
            case kMips64CmpS:
                return MoveLatency() + CompareF32Latency();
            case kMips64AddS:
                return Latency::ADD_S;
            case kMips64SubS:
                return Latency::SUB_S;
            case kMips64MulS:
                return Latency::MUL_S;
            case kMips64DivS:
                return Latency::DIV_S;
            case kMips64ModS:
                return PrepareCallCFunctionLatency() + MovToFloatParametersLatency() + CallCFunctionLatency() + MovFromFloatResultLatency();
            case kMips64AbsS:
                return Latency::ABS_S;
            case kMips64NegS:
                return NegdLatency();
            case kMips64SqrtS:
                return Latency::SQRT_S;
            case kMips64MaxS:
                return Latency::MAX_S;
            case kMips64MinS:
                return Latency::MIN_S;
            case kMips64CmpD:
                return MoveLatency() + CompareF64Latency();
            case kMips64AddD:
                return Latency::ADD_D;
            case kMips64SubD:
                return Latency::SUB_D;
            case kMips64MulD:
                return Latency::MUL_D;
            case kMips64DivD:
                return Latency::DIV_D;
            case kMips64ModD:
                return PrepareCallCFunctionLatency() + MovToFloatParametersLatency() + CallCFunctionLatency() + MovFromFloatResultLatency();
            case kMips64AbsD:
                return Latency::ABS_D;
            case kMips64NegD:
                return NegdLatency();
            case kMips64SqrtD:
                return Latency::SQRT_D;
            case kMips64MaxD:
                return Latency::MAX_D;
            case kMips64MinD:
                return Latency::MIN_D;
            case kMips64Float64RoundDown:
            case kMips64Float64RoundTruncate:
            case kMips64Float64RoundUp:
            case kMips64Float64RoundTiesEven:
                return Float64RoundLatency();
            case kMips64Float32RoundDown:
            case kMips64Float32RoundTruncate:
            case kMips64Float32RoundUp:
            case kMips64Float32RoundTiesEven:
                return Float32RoundLatency();
            case kMips64Float32Max:
                return Float32MaxLatency();
            case kMips64Float64Max:
                return Float64MaxLatency();
            case kMips64Float32Min:
                return Float32MinLatency();
            case kMips64Float64Min:
                return Float64MinLatency();
            case kMips64Float64SilenceNaN:
                return Latency::SUB_D;
            case kMips64CvtSD:
                return Latency::CVT_S_D;
            case kMips64CvtDS:
                return Latency::CVT_D_S;
            case kMips64CvtDW:
                return Latency::MTC1 + Latency::CVT_D_W;
            case kMips64CvtSW:
                return Latency::MTC1 + Latency::CVT_S_W;
            case kMips64CvtSUw:
                return 1 + Latency::DMTC1 + Latency::CVT_S_L;
            case kMips64CvtSL:
                return Latency::DMTC1 + Latency::CVT_S_L;
            case kMips64CvtDL:
                return Latency::DMTC1 + Latency::CVT_D_L;
            case kMips64CvtDUw:
                return 1 + Latency::DMTC1 + Latency::CVT_D_L;
            case kMips64CvtDUl:
                return 2 * Latency::BRANCH + 3 + 2 * Latency::DMTC1 + 2 * Latency::CVT_D_L + Latency::ADD_D;
            case kMips64CvtSUl:
                return 2 * Latency::BRANCH + 3 + 2 * Latency::DMTC1 + 2 * Latency::CVT_S_L + Latency::ADD_S;
            case kMips64FloorWD:
                return Latency::FLOOR_W_D + Latency::MFC1;
            case kMips64CeilWD:
                return Latency::CEIL_W_D + Latency::MFC1;
            case kMips64RoundWD:
                return Latency::ROUND_W_D + Latency::MFC1;
            case kMips64TruncWD:
                return Latency::TRUNC_W_D + Latency::MFC1;
            case kMips64FloorWS:
                return Latency::FLOOR_W_S + Latency::MFC1;
            case kMips64CeilWS:
                return Latency::CEIL_W_S + Latency::MFC1;
            case kMips64RoundWS:
                return Latency::ROUND_W_S + Latency::MFC1;
            case kMips64TruncWS:
                return Latency::TRUNC_W_S + Latency::MFC1 + 2 + MovnLatency();
            case kMips64TruncLS:
                return TruncLSLatency(instr->OutputCount() > 1);
            case kMips64TruncLD:
                return TruncLDLatency(instr->OutputCount() > 1);
            case kMips64TruncUwD:
                // Estimated max.
                return CompareF64Latency() + 2 * Latency::BRANCH + 2 * Latency::TRUNC_W_D + Latency::SUB_D + OrLatency() + Latency::MTC1 + Latency::MFC1 + Latency::MTHC1 + 1;
            case kMips64TruncUwS:
                // Estimated max.
                return CompareF32Latency() + 2 * Latency::BRANCH + 2 * Latency::TRUNC_W_S + Latency::SUB_S + OrLatency() + Latency::MTC1 + 2 * Latency::MFC1 + 2 + MovzLatency();
            case kMips64TruncUlS:
                return TruncUlSLatency();
            case kMips64TruncUlD:
                return TruncUlDLatency();
            case kMips64BitcastDL:
                return Latency::DMFC1;
            case kMips64BitcastLD:
                return Latency::DMTC1;
            case kMips64Float64ExtractLowWord32:
                return Latency::MFC1;
            case kMips64Float64InsertLowWord32:
                return Latency::MFHC1 + Latency::MTC1 + Latency::MTHC1;
            case kMips64Float64ExtractHighWord32:
                return Latency::MFHC1;
            case kMips64Float64InsertHighWord32:
                return Latency::MTHC1;
            case kMips64Seb:
            case kMips64Seh:
                return 1;
            case kMips64Lbu:
            case kMips64Lb:
            case kMips64Lhu:
            case kMips64Lh:
            case kMips64Lwu:
            case kMips64Lw:
            case kMips64Ld:
            case kMips64Sb:
            case kMips64Sh:
            case kMips64Sw:
            case kMips64Sd:
                return AlignedMemoryLatency();
            case kMips64Lwc1:
                return Lwc1Latency();
            case kMips64Ldc1:
                return Ldc1Latency();
            case kMips64Swc1:
                return Swc1Latency();
            case kMips64Sdc1:
                return Sdc1Latency();
            case kMips64Ulhu:
            case kMips64Ulh:
                return UlhuLatency();
            case kMips64Ulwu:
                return UlwuLatency();
            case kMips64Ulw:
                return UlwLatency();
            case kMips64Uld:
                return UldLatency();
            case kMips64Ulwc1:
                return Ulwc1Latency();
            case kMips64Uldc1:
                return Uldc1Latency();
            case kMips64Ush:
                return UshLatency();
            case kMips64Usw:
                return UswLatency();
            case kMips64Usd:
                return UsdLatency();
            case kMips64Uswc1:
                return Uswc1Latency();
            case kMips64Usdc1:
                return Usdc1Latency();
            case kMips64Push: {
                int latency = 0;
                if (instr->InputAt(0)->IsFPRegister()) {
                    latency = Sdc1Latency() + DsubuLatency(false);
                } else {
                    latency = PushLatency();
                }
                return latency;
            }
            case kMips64Peek: {
                int latency = 0;
                if (instr->OutputAt(0)->IsFPRegister()) {
                    auto op = LocationOperand::cast(instr->OutputAt(0));
                    switch (op->representation()) {
                    case MachineRepresentation::kFloat64:
                        latency = Ldc1Latency();
                        break;
                    case MachineRepresentation::kFloat32:
                        latency = Latency::LWC1;
                        break;
                    default:
                        UNREACHABLE();
                    }
                } else {
                    latency = AlignedMemoryLatency();
                }
                return latency;
            }
            case kMips64StackClaim:
                return DsubuLatency(false);
            case kMips64StoreToStackSlot: {
                int latency = 0;
                if (instr->InputAt(0)->IsFPRegister()) {
                    if (instr->InputAt(0)->IsSimd128Register()) {
                        latency = 1; // Estimated value.
                    } else {
                        latency = Sdc1Latency();
                    }
                } else {
                    latency = AlignedMemoryLatency();
                }
                return latency;
            }
            case kMips64ByteSwap64:
                return ByteSwapSignedLatency();
            case kMips64ByteSwap32:
                return ByteSwapSignedLatency();
            case kWord32AtomicLoadInt8:
            case kWord32AtomicLoadUint8:
            case kWord32AtomicLoadInt16:
            case kWord32AtomicLoadUint16:
            case kWord32AtomicLoadWord32:
                return 2;
            case kWord32AtomicStoreWord8:
            case kWord32AtomicStoreWord16:
            case kWord32AtomicStoreWord32:
                return 3;
            case kWord32AtomicExchangeInt8:
                return Word32AtomicExchangeLatency(true, 8);
            case kWord32AtomicExchangeUint8:
                return Word32AtomicExchangeLatency(false, 8);
            case kWord32AtomicExchangeInt16:
                return Word32AtomicExchangeLatency(true, 16);
            case kWord32AtomicExchangeUint16:
                return Word32AtomicExchangeLatency(false, 16);
            case kWord32AtomicExchangeWord32:
                return 2 + LlLatency(0) + 1 + ScLatency(0) + BranchShortLatency() + 1;
            case kWord32AtomicCompareExchangeInt8:
                return Word32AtomicCompareExchangeLatency(true, 8);
            case kWord32AtomicCompareExchangeUint8:
                return Word32AtomicCompareExchangeLatency(false, 8);
            case kWord32AtomicCompareExchangeInt16:
                return Word32AtomicCompareExchangeLatency(true, 16);
            case kWord32AtomicCompareExchangeUint16:
                return Word32AtomicCompareExchangeLatency(false, 16);
            case kWord32AtomicCompareExchangeWord32:
                return 3 + LlLatency(0) + BranchShortLatency() + 1 + ScLatency(0) + BranchShortLatency() + 1;
            case kMips64AssertEqual:
                return AssertLatency();
            default:
                return 1;
            }
        }

    } // namespace compiler
} // namespace internal
} // namespace v8
